#ifndef DATABASE_H__
#define DATABASE_H__

#include "database_def.h"
#include "query_callback.h"
#include "sql_operation.h"
#include "query_result.h"
#include <stdarg.h>
#include <stdio.h>

namespace engine
{
	class Database
	{
	public:
		bool execute(const char *fmt, ...);

		template<typename T>
		bool query(T* obj, void (T::*method)(QueryResultSet*), const char *fmt, ...);
		template<typename T, typename ParamType1>
		bool query(T* obj, void (T::*method)(QueryResultSet*, ParamType1), ParamType1 param1, const char *fmt, ...);
		template<typename T, typename ParamType1, typename ParamType2>
		bool query(T* obj, void (T::*method)(QueryResultSet*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *fmt, ...);
		template<typename T, typename ParamType1, typename ParamType2, typename ParamType3>
		bool query(T* obj, void (T::*method)(QueryResultSet*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *fmt, ...);
		template<typename T, typename ParamType1, typename ParamType2, typename ParamType3, typename ParamType4>
		bool query(T* obj, void (T::*method)(QueryResultSet*, ParamType1, ParamType2, ParamType3, ParamType4), ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4, const char *fmt, ...);
		template<typename T, typename ParamType1, typename ParamType2, typename ParamType3, typename ParamType4, typename ParamType5>
		bool query(T* obj, void (T::*method)(QueryResultSet*, ParamType1, ParamType2, ParamType3, ParamType4, ParamType5), ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4, ParamType5 param5, const char *fmt, ...);
		template<typename T, typename ParamType1, typename ParamType2, typename ParamType3, typename ParamType4, typename ParamType5, typename ParamType6>
		bool query(T* obj, void (T::*method)(QueryResultSet*, ParamType1, ParamType2, ParamType3, ParamType4, ParamType5, ParamType6), ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4, ParamType5 param5, ParamType6 param6, const char *fmt, ...);

		void handleResults();

		void printStat();

		DatabaseThread* getMinLoadThread();

	protected:
		bool push(SqlOperation* op);

		std::vector<DatabaseThread*> mThreads;
	};

	template<typename T>
	bool Database::query(T* obj, void (T::*method)(QueryResultSet*), const char *fmt, ...)
	{
		QUERY_BODY(fmt, buf)
		return push(new SqlQuery(buf, new QueryCallback<T>(obj, method)));
	}

	template<typename T, typename ParamType1>
	bool Database::query(T* obj, void (T::*method)(QueryResultSet*, ParamType1), ParamType1 param1, const char *fmt, ...)
	{
		QUERY_BODY(fmt, buf)
		return push(new SqlQuery(buf, new QueryCallback<T, ParamType1>(obj, method, param1)));
	}

	template<typename T, typename ParamType1, typename ParamType2>
	bool Database::query(T* obj, void (T::*method)(QueryResultSet*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *fmt, ...)
	{
		QUERY_BODY(fmt, buf)
		return push(new SqlQuery(buf, new QueryCallback<T, ParamType1, ParamType2>(obj, method, param1, param2)));
	}

	template<typename T, typename ParamType1, typename ParamType2, typename ParamType3>
	bool Database::query(T* obj, void (T::*method)(QueryResultSet*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *fmt, ...)
	{
		QUERY_BODY(fmt, buf)
		return push(new SqlQuery(buf, new QueryCallback<T, ParamType1, ParamType2, ParamType3>(obj, method, param1, param2, param3)));
	}

	template<typename T, typename ParamType1, typename ParamType2, typename ParamType3, typename ParamType4>
	bool Database::query(T* obj, void (T::*method)(QueryResultSet*, ParamType1, ParamType2, ParamType3, ParamType4), ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4, const char *fmt, ...)
	{
		QUERY_BODY(fmt, buf)
		return push(new SqlQuery(buf, new QueryCallback<T, ParamType1, ParamType2, ParamType3, ParamType4>(obj, method, param1, param2, param3, param4)));
	}

	template<typename T, typename ParamType1, typename ParamType2, typename ParamType3, typename ParamType4, typename ParamType5>
	bool Database::query(T* obj, void (T::*method)(QueryResultSet*, ParamType1, ParamType2, ParamType3, ParamType4, ParamType5), ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4, ParamType5 param5, const char *fmt, ...)
	{
		QUERY_BODY(fmt, buf)
		return push(new SqlQuery(buf, new QueryCallback<T, ParamType1, ParamType2, ParamType3, ParamType4, ParamType5>(obj, method, param1, param2, param3, param4, param5)));
	}

	template<typename T, typename ParamType1, typename ParamType2, typename ParamType3, typename ParamType4, typename ParamType5, typename ParamType6>
	bool Database::query(T* obj, void (T::*method)(QueryResultSet*, ParamType1, ParamType2, ParamType3, ParamType4, ParamType5, ParamType6), ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4, ParamType5 param5, ParamType6 param6, const char *fmt, ...)
	{
		QUERY_BODY(fmt, buf)
		return push(new SqlQuery(buf, new QueryCallback<T, ParamType1, ParamType2, ParamType3, ParamType4, ParamType5, ParamType6>(obj, method, param1, param2, param3, param4, param5, param6)));
	}
}

#endif
